#include "VertexList.h"


VertexList::VertexList(int initialSize):
	m_Data(0),
	m_CurrentSize(-1),
	m_InitialSize(initialSize),
	m_CurrentCapacity(initialSize),
	m_SizePerVertex(0)
{
}

VertexList::VertexList(int initialSize, vector<SEMANTIC> semanticList, vector<int> sizeList,bool adjustCurrentSize)
: m_InitialSize(initialSize),
m_SemanticList(semanticList),
m_CurrentCapacity(initialSize),
m_CurrentSize(-1),
m_SizeList(sizeList)
{
	m_SizePerVertex = 0;
	vector<int>::iterator it;
	for ( it = m_SizeList.begin(); it!= m_SizeList.end(); it++)
	{
		m_SizePerVertex += (*it);
	}
	m_Data = new float[m_InitialSize*m_SizePerVertex];	
	if ( adjustCurrentSize )
		m_CurrentSize = initialSize-1;
}

VertexList::~VertexList(void)
{
	if ( m_Data != NULL )
		delete[] m_Data;
}

void VertexList::AddSemantic(SEMANTIC semantic, int size)
{
	m_SizeList.push_back(size);
	m_SemanticList.push_back(semantic);

	int m_NewSizePerVertex = m_SizePerVertex + size;
	float * m_NewData = new float[m_CurrentCapacity*m_NewSizePerVertex];
	
	if (m_Data != NULL ){
		// copy the old dat into the new data.
		float * oldStart = m_Data;
		float * newStart = m_NewData;
		for (int i =0; i < m_CurrentCapacity; ++i ){
			memcpy(newStart,oldStart,m_SizePerVertex*sizeof(float));
			oldStart += m_SizePerVertex;
			newStart += m_NewSizePerVertex;
		}
		delete[] m_Data;
	}
	m_Data = m_NewData;
	m_SizePerVertex = m_NewSizePerVertex;
}

void VertexList::AddVertexData(int vertexIndex, SEMANTIC semantic, DAEFloat4 * pVector)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,semantic);
	// copy 3 floats
	memcpy(vertexSemantic,pVector->GetValuePointer(),pVector->GetSizeInBytes());
	this->UpdateCurrentSize(vertexIndex);
}
void VertexList::AddVertexData(int vertexIndex, int semanticOffset, DAEFloat4 * pVector)
{
	if ( vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + vertexIndex*m_SizePerVertex + semanticOffset;
	memcpy(vertexSemantic,pVector->GetValuePointer(),pVector->GetSizeInBytes());
	this->UpdateCurrentSize(vertexIndex);
}
void VertexList::GetVertexData(int vertexIndex, SEMANTIC semantic, DAEFloat4 *pVector)
{
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,semantic);
	// copy 3 float
	pVector->x = vertexSemantic[0];
	pVector->y = vertexSemantic[1];
	pVector->z = vertexSemantic[2];
	pVector->w = vertexSemantic[3];
}
void VertexList::GetVertexData(int vertexIndex, int semanticOffset, DAEFloat4 *pVector)
{
	float * vertexPointer = m_Data + vertexIndex*m_SizePerVertex + semanticOffset;
	pVector->x = vertexPointer[0];
	pVector->y = vertexPointer[1];
	pVector->z = vertexPointer[2];
	pVector->w = vertexPointer[3];
}

void VertexList::AddVertexData(int vertexIndex, SEMANTIC s, DAEFloat3 * pVector)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	// copy 3 floats
	memcpy(vertexSemantic,pVector->GetValuePointer(),pVector->GetSizeInBytes());
	this->UpdateCurrentSize(vertexIndex);
}

void VertexList::AddVertexData(int vertexIndex, int semanticOffset, DAEFloat3 * pVector)
{
	if ( vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + vertexIndex*m_SizePerVertex + semanticOffset;
	memcpy(vertexSemantic,pVector->GetValuePointer(),pVector->GetSizeInBytes());
	this->UpdateCurrentSize(vertexIndex);

}
	
void VertexList::GetVertexData(int vertexIndex, SEMANTIC s, DAEFloat3 *pVector)
{
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	// copy 3 float
	pVector->x = vertexSemantic[0];
	pVector->y = vertexSemantic[1];
	pVector->z = vertexSemantic[2];
}

void VertexList::GetVertexData(int vertexIndex, int semanticOffset, DAEFloat3 *pVector)
{
	float * vertexPointer = m_Data + vertexIndex*m_SizePerVertex + semanticOffset;
	pVector->x = vertexPointer[0];
	pVector->y = vertexPointer[1];
	pVector->z = vertexPointer[2];
}

void VertexList::GetVertexData(int vertexIndex, int semanticOffset, DAEFloat2 *pVector)
{
	float * vertexSemantic = m_Data + vertexIndex*m_SizePerVertex + semanticOffset;
	// copy 2 float
	pVector->x = vertexSemantic[0];
	pVector->y = vertexSemantic[1];
}


void VertexList::AddVertexData(int vertexIndex, SEMANTIC s, DAEFloat2 * pVector)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	// copy 2 floats
	memcpy(vertexSemantic,pVector->GetValuePointer(),pVector->GetSizeInBytes());
	this->UpdateCurrentSize(vertexIndex);
}

void VertexList::AddVertexData(int vertexIndex, int semanticOffset, DAEFloat2 * pVector)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + vertexIndex*m_SizePerVertex +semanticOffset;
	// copy 2 floats
	memcpy(vertexSemantic,pVector->GetValuePointer(),pVector->GetSizeInBytes());
	this->UpdateCurrentSize(vertexIndex);
}

void VertexList::GetVertexData(int vertexIndex, SEMANTIC s, DAEFloat2 *pVector)
{	
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	// copy 2 floats
	pVector->x = vertexSemantic[0];
	pVector->y = vertexSemantic[1];
}



void VertexList::AddVertexData(int vertexIndex, SEMANTIC s, float value)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	*vertexSemantic = value;
}

void VertexList::AddVertexData(int vertexIndex, int semanticOffset, float value)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + vertexIndex * m_SizePerVertex + semanticOffset;
	*vertexSemantic = value;
}
	
float VertexList::GetVertexData(int vertexIndex, SEMANTIC s)
{
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	return *vertexSemantic;
}

float VertexList::GetVertexData(int vertexIndex, int semanticOffset)
{
	float * vertexSemantic = m_Data + vertexIndex*m_SizePerVertex+semanticOffset;
	return *vertexSemantic;
}

void VertexList::AddVertexData(int vertexIndex, SEMANTIC s,float * dataPtr, int size)
{
	if (vertexIndex >= m_CurrentCapacity)
		Grow(m_CurrentCapacity*2);
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	memcpy(vertexSemantic,dataPtr,size*sizeof(float));
	this->UpdateCurrentSize(vertexIndex);
}

void VertexList::GetVertexData(int vertexIndex, SEMANTIC s, float * dataPtr, int size)
{
	float * vertexSemantic = m_Data + this->GetOffset(vertexIndex,s);
	memcpy(dataPtr,vertexSemantic,size*sizeof(float));
}

void VertexList::NormalizeDataBySemantic(SEMANTIC s)
{
	int offset = this->GetOffset(s);
	if (offset < 0)
		return;
	int size = this->GetSize();
	int semanticSize = this->GetSemanticSize(s);
	float * start = m_Data+offset;
	switch(semanticSize){
		case 2:
			for (int i = 0; i < size; i++)
			{
				DAEFloat2* toNormalize = (DAEFloat2*)start;
				toNormalize->Normalize();
				start += m_SizePerVertex;
			}
			break;
		case 3:
			for (int i = 0; i < size; i++)
			{
				DAEFloat3* toNormalize = (DAEFloat3*)start;
				toNormalize->Normalize();
				start += m_SizePerVertex;
			}
			break;
	}	
}

void VertexList::TransformVertexSemantic(DAEMatrix& matrix,SEMANTIC s)
{
	int offset= this->GetOffset(s);
	if ( offset < 0 )
		return;
	int size = this->GetSize();
	int semanticSize = this->GetSemanticSize(s);
	float * start = m_Data+offset;
	if ( semanticSize == 3)
	{
		for ( int i = 0 ; i < size ; i++ ){
			DAEFloat3* toTransform = (DAEFloat3*)start;
			matrix.TransformVector(*toTransform,*toTransform);
			start += m_SizePerVertex;
		}
	}
}

void VertexList::FillSemantic(SEMANTIC s,DAEFloat3* fillValue)
{
	int offset = this->GetOffset(s);
	if (offset<0)
		return;
	int semanticSize = this->GetSemanticSize(s);
	if (semanticSize != 3)
		return;
	float* start = m_Data+offset;
	for ( int i=0;i< m_CurrentCapacity;i++)
	{
		memcpy(start,fillValue,3*sizeof(float));
		start += m_SizePerVertex;
	}
}

void VertexList::AddNormalForTri(int v1, int v2, int v3)
{
	int posOffset = this->GetOffset(POSITION);
	int normalOffset = this->GetOffset(NORMAL);
	this->AddNormalForTri(posOffset,normalOffset,v1,v2,v3);
}

void VertexList::AddNormalForTri(int posOffset, int normalOffset, int v1, int v2, int v3)
{
	DAEFloat3 first(0,0,0);
	this->GetVertexData(v1, posOffset, &first);
	DAEFloat3 second(0,0,0);
	this->GetVertexData(v2, posOffset, &second);
	DAEFloat3 third(0,0,0);
	this->GetVertexData(v3, posOffset, &third);
	DAEFloat3 axis1;
	second.Subtract(axis1,first);
	DAEFloat3 axis2; 
	third.Subtract(axis2,first);
	DAEFloat3 normal;
	axis1.CrossAndNormalize(normal,axis2);
	
	// current normal
	DAEFloat3 normal1, normal2, normal3;
	
	this->GetVertexData(v1, normalOffset, &normal1);
	this->GetVertexData(v2, normalOffset, &normal2);
	this->GetVertexData(v3, normalOffset, &normal3);
	
	normal1.Add(normal1,normal);
	normal2.Add(normal2,normal);
	normal3.Add(normal3,normal);

	this->AddVertexData(v1, normalOffset, &normal1);
	this->AddVertexData(v2, normalOffset, &normal2);
	this->AddVertexData(v3, normalOffset, &normal3);
}

void VertexList::Grow(int newCapacity)
{
	if ( newCapacity == 0 )
		newCapacity = 2;
	float * pData = new float[newCapacity* m_SizePerVertex];
	memcpy(pData, m_Data, m_CurrentCapacity * m_SizePerVertex * sizeof(float));
	delete[]  m_Data;
	m_Data = pData;
	m_CurrentCapacity = newCapacity;
}

int VertexList::GetOffset(int vertexIndex,SEMANTIC s)
{
	return vertexIndex * m_SizePerVertex+GetOffset(s);
}

int VertexList::GetOffset(SEMANTIC s)
{
	vector<SEMANTIC>::const_iterator semanticIt;
	vector<int>::const_iterator sizeIt;
	int offset = 0;
	for ( semanticIt = m_SemanticList.begin(), sizeIt = m_SizeList.begin();
		semanticIt != m_SemanticList.end() && sizeIt != m_SizeList.end();
		semanticIt++, sizeIt++)
	{	
		if ( s == (*semanticIt) )
			return offset;
		offset += (*sizeIt);
	}
	// no semantic was found so return -1
	return -1;
}

int VertexList::GetSemanticSize(SEMANTIC s){
	vector<SEMANTIC>::const_iterator semanticIt;
	vector<int>::const_iterator sizeIt;
	for ( semanticIt = m_SemanticList.begin(), sizeIt = m_SizeList.begin();
		semanticIt != m_SemanticList.end() && sizeIt != m_SizeList.end();
		semanticIt++, sizeIt++)
	{	
		if ( s == (*semanticIt) )
			return (*sizeIt);
	}
	return 0;
}

void VertexList::UpdateCurrentSize(int index){
	if (index>m_CurrentSize)
		m_CurrentSize = index;
}

int VertexList::GetSize(){
	return m_CurrentSize + 1;
}


SEMANTIC VertexList::GetSemantic(unsigned int index)
{
	if (index < m_SemanticList.size() )
		return m_SemanticList[index];
	else
		return POSITION;
}

int VertexList::GetSemanticSize(unsigned int index)
{
	if ( index < m_SemanticList.size() )
		return m_SizeList[index];
	else
		return 0;
}